﻿--[[
	Widget name	  	Script
	Author     	 	Kurapica
--]]

-- Script
do
	IGAS:NewAddon("IGAS_Studio")

	local _WidgetName = "Script"
    local _Base = "MultiLineTextBox"

    -- Scripts
	local _SystemEventDB = CreateHelpDB("SystemEvent")

	-- Init Script Type
	local _LstScriptType = {}
	do
		for script in pairs(IGAS.GUI.Enum.ScriptType) do
			_LstScriptType[script] = true
		end

		for _, widget in pairs(IGAS.GUI.Widget) do
			for script in pairs(widget.ScriptType or {}) do
				_LstScriptType[script] = true
			end
		end
	end

	-- CodeHelp Init
	_CodeHelpPool = {}
	_CodeHelpPool[_G] = CreateFrame(Widget.CodeHelper, "CodeHelper_G", coreF, _G)
	_CodeHelpPool["Addon"] = {
		["Function"] = CreateFrame(Widget.CodeHelper, "CodeHelper_Addon", coreF, "Addon", "Function"),
	}

	-- Gather Frame
	local function GatherFrame(content, frames)
		for str in gmatch(content, "_Addon:AddFrame%(([_%a][_%w]*)") do
			local frmType = strmatch(content, ""..str.."%s*=%s*CreateFrame%(\"([_%a][_%w]*)\"")

			if frmType and IGAS.GUI.Widget[frmType] then
				frames[str] = IGAS.GUI.Widget[frmType]
			end
		end
	end

	local function GatherFile(file, frames)
		if file.Type == "Frame" then
			GatherFrame(file.Designer, frames)
		end
	end

	local function GatherFolder(folder, frames)
		for _, file in ipairs(folder) do
			if type(file) == "table" then
				if file.Type == "Folder" then
					GatherFolder(file, frames)
				else
					GatherFile(file, frames)
				end
			end
		end
	end

	local function GatherAddon(addon)
		local frames = {}

		for _, f in ipairs(addon) do
			if type(f) == "table" then
				if f.Type == "Folder" then
					GatherFolder(f, frames)
				else
					GatherFile(f, frames)
				end
			end
		end

		return frames
	end

	-- Load Help info
	local function LoadHelp(self)
		local cboName = self.Parent.CboName
		local Keys, Items
		local lstSort = {}

		-- Default
		cboName:Clear()

		cboName:AddItem({["Keys"] = {}, ["Items"] = {}}, "(Global)")

		if self.__File.Type == "Frame" and self.__Part == "Script" then
			Log(1, "[Script][LoadHelp][Frame]"..self.__File.Name)
			-- Frames
			local f = CreateFrame("Frame", "HelpDesigner", self)
			f.Visible = false

			local d = CreateFrame(Widget.Designer, "Designer", f, self.__Addon, self.__File)

			d:Load()

			self.__Designer = d

			local lstFrame = {}
			local lstName = {}

			for name, frame in pairs(d.__Env) do
				if type(name) == "string" and name ~= "UIParent" and type(frame) == "table" and frame.IsIGASFrame and type(frame.IsIGASFrame) == "function" then
					lstFrame[name] = frame
					tinsert(lstName, name)
				end
			end

			sort(lstName)

			for _, name in ipairs(lstName) do
				Log(1, "[Script][LoadHelp][Load]"..name)

				local frame = lstFrame[name]

				Keys = {}
				Items = {}

				tinsert(Keys, "")
				tinsert(Items, "")

				-- Events
				-- Temp list
				wipe(lstSort)
				for event in pairs(frame.__RegisterEventList or {}) do
					tinsert(lstSort, event)
				end

				-- Sort list
				sort(lstSort)

				-- Set keys and items
				for _, event in ipairs(lstSort) do
					tinsert(Keys, _SystemEventDB:GetCodeHelp(event, "Body"))
					tinsert(Items, event)
				end

				-- Scripts
				wipe(lstSort)
				for script in pairs(GetTrueFrame(frame):GetObjectType().ScriptType or {}) do
					_LstScriptType[script] = true
				end
				for script in pairs(_LstScriptType) do
					if GetTrueFrame(frame):HasScript(script) then
						tinsert(lstSort, script)
					end
				end

				-- Sort list
				sort(lstSort)

				-- Set keys and items
				for _, script in ipairs(lstSort) do
					tinsert(Keys, CreateHelpDB(GetTrueObject(frame), "ScriptType"):GetCodeHelp(script, "Body"))
					tinsert(Items, script)
				end

				cboName:AddItem({["Keys"] = Keys, ["Items"] = Items}, name)
			end

			-- CodeHelper
			local chItem = CreateFrame(Widget.CodeHelper, "CodeHelper_ItemList", self)
			chItem:Clear()

			for _, name in ipairs(lstName) do
				local widget = GetTrueObject(lstFrame[name])
				chItem:AddItem(widget, name)
				if not _CodeHelpPool[widget] then
					_CodeHelpPool[widget] = {}
					_CodeHelpPool[widget]["Function"] = CreateFrame(Widget.CodeHelper, "CodeHelper_Function_"..widget.WidgetName, coreF, widget, "Function")
					_CodeHelpPool[widget]["Property"] = CreateFrame(Widget.CodeHelper, "CodeHelper_Property_"..widget.WidgetName, coreF, widget, "Property")
				end
			end

			wipe(lstFrame)
			wipe(lstName)
		elseif self.__File.Type == "Script" and self.__File.Name == self.__Addon[0].Name then
			-- Addon
			Keys = {}
			Items = {}

			--- RegisterEvents
			if self.__Addon.__RegisterEventList then
				-- Temp list
				wipe(lstSort)
				for event in pairs(self.__Addon.__RegisterEventList) do
					tinsert(lstSort, event)
				end

				-- Sort list
				sort(lstSort)

				-- Set keys and items
				tinsert(Keys, "")
				tinsert(Items, "")

				for _, event in ipairs(lstSort) do
					tinsert(Keys, _SystemEventDB:GetCodeHelp(event, "Body"))
					tinsert(Items, event)
				end
			end

			--- Scripts
			wipe(lstSort)
			local DB =  CreateHelpDB("Addon", "ScriptType")

			for script in pairs(DB) do
				tinsert(lstSort, script)
			end

			-- Sort list
			sort(lstSort)

			-- Set keys and items
			for _, script in ipairs(lstSort) do
				tinsert(Keys, DB:GetCodeHelp(script, "Body"))
				tinsert(Items, script)
			end

			-- AddItem to cboName
			cboName:AddItem({["Keys"] = Keys, ["Items"] = Items}, "_Addon")

			-- CodeHelper
			local chItem = CreateFrame(Widget.CodeHelper, "CodeHelper_ItemList", self)
			chItem:Clear()

			chItem:AddItem("Addon", "_Addon")

			wipe(lstSort)

			local frames = GatherAddon(self.__Addon)

			for name in pairs(frames) do
				tinsert(lstSort, name)
			end

			-- Sort list
			sort(lstSort)

			for _, name in ipairs(lstSort) do
				local widget = frames[name]
				chItem:AddItem(widget, name)
				if not _CodeHelpPool[widget] then
					_CodeHelpPool[widget] = {}
					_CodeHelpPool[widget]["Function"] = CreateFrame(Widget.CodeHelper, "CodeHelper_Function_"..widget.WidgetName, coreF, widget, "Function")
					_CodeHelpPool[widget]["Property"] = CreateFrame(Widget.CodeHelper, "CodeHelper_Property_"..widget.WidgetName, coreF, widget, "Property")
				end
			end
		end

		-- Common

	end

	-- Frame's Scripts
	local function Name_OnValueChanged(self, value)
		self.Parent.CboFunc.Keys = value.Keys
		self.Parent.CboFunc.Items = value.Items
		self.Parent.CboFunc.Value = ""
	end

	local function Func_OnValueChanged(self, value)
		local name = self.Parent.CboName.Text
		local txtCode = self._Code

		if name and name ~= "" and value and value ~= "" then
			local func = "function "..name..":"..strmatch(value, "(.*)%b()")

			if strfind(txtCode.Text, func, 1) then
				txtCode.CursorPosition = strfind(txtCode.Text, func, 1)
			else
				txtCode.Text = txtCode.Text.."\nfunction "..name..":"..value.."\n    \nend\n"

				txtCode.CursorPosition = strfind(txtCode.Text, func, 1)
			end
		end
	end

	local function OnCursorChanged(self, x, y, w, h)
		self._X = x
		self._Y = y
		self._W = w
		self._H = h
	end

	local function OnMouseUp(self, button)
		if button == "MiddleButton" then
			_CodeHelpPool[_G]:Show(self, self._X, self._Y, self._W, self._H)
		elseif button == "RightButton" and self.CodeHelper_ItemList then
			self.CodeHelper_ItemList:Show(self, self._X, self._Y, self._W, self._H)
		end
	end

	local function GetPrevID(self)
		local substr = strsub(self:GetText(true), 1, self.CursorPosition - 1)
		local id = strmatch(substr, "([_%a][_%w]*)$")
		local ed

		if id and id == "self" then
			substr = Indent.decode(substr)
			for str in gmatch(substr, "function%s*[_%a][_%w]*:[_%a][_%w]*") do
				id = strmatch(str, "function%s*([_%a][_%w]*):")
			end
		end

		return id
	end

	local function OnChar(self, char)
		if char == "." then
			local id = GetPrevID(self)

			if id and self.CodeHelper_ItemList then
				for i = 1, self.CodeHelper_ItemList.ItemCount do
					if id == self.CodeHelper_ItemList.Items[i] and _CodeHelpPool[self.CodeHelper_ItemList.Keys[i]]["Property"] then
						_CodeHelpPool[self.CodeHelper_ItemList.Keys[i]]["Property"]:Show(self, self._X, self._Y, self._W, self._H)
					end
				end
			end
		elseif char == ":" then
			local id = GetPrevID(self)

			if id and self.CodeHelper_ItemList then
				for i = 1, self.CodeHelper_ItemList.ItemCount do
					if id == self.CodeHelper_ItemList.Items[i] and _CodeHelpPool[self.CodeHelper_ItemList.Keys[i]]["Function"] then
						_CodeHelpPool[self.CodeHelper_ItemList.Keys[i]]["Function"]:Show(self, self._X, self._Y, self._W, self._H)
					end
				end
			end
		end
	end

	-- ScriptType
	local _ScriptType = {
	}

	-- Function
	local _Function = {
        -- Dispose, release resource
        ["Dispose"] = function(self)
            -- Call super's dispose
			self:CallMethod(_Base, "Dispose")
        end,

		["Save"] = function(self)
			self.__File[self.__Part] = self.Text
		end,

		["Load"] = function(self)
			Log(1, "[Script][Load]"..self.__File.Name)
			self.Text = self.__File[self.__Part]
			LoadHelp(self)
		end,

		["Clear"] = function(self)
			-- Nothing need to do
		end,
    }

	-- Property
	local _Property = {
    }

    -- New
    local function _New(name, parent, addon, file, part)

		local frame = CreateFrame("MultiLineTextBox",name,parent)

		local cboName = CreateFrame("ComboBox", "CboName", parent)
		cboName:SetPoint("TOPLEFT", parent, "TOPLEFT", 4, -4)
		cboName:SetPoint("RIGHT", parent, "CENTER", -1, 0)

		local cboFunc = CreateFrame("ComboBox", "CboFunc", parent)
		cboFunc:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -4, -4)
		cboFunc:SetPoint("LEFT", parent, "CENTER", 1, 0)
		cboFunc._Code = frame

		local txtMsg = CreateFrame("FontString", "Message", parent)
		txtMsg:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 4, 0)
		txtMsg:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -4, 0)
		txtMsg.Height = 25

		frame:SetPoint("TOPLEFT", cboName, "BOTTOMLEFT")
		frame:SetPoint("BOTTOMRIGHT", txtMsg, "TOPRIGHT")
		frame.__Addon = addon
		frame.__File = file
		frame.__Part = part

		cboName.OnValueChanged = Name_OnValueChanged
		cboFunc.OnValueChanged = Func_OnValueChanged

		frame.OnCursorChanged = OnCursorChanged
		frame.OnMouseUp = OnMouseUp
		frame.OnChar = OnChar

		-- Indents and Purposes
		Indent.enable(frame.__Text, nil, 4)

        return frame
    end

    local _WidgetInfo = {
        ["WidgetName"] = _WidgetName,
        ["Base"] = _Base,
        ["Function"] = _Function,
        ["Property"] = _Property,
        ["ScriptType"] = _ScriptType,
        ["New"] = _New,
		-- Special Item
    }

    Widget[_WidgetName] = IGAS:NewWidget(_WidgetInfo)
end